namespace Vanilla.UI

import Vanilla

import System
import Tao.Sdl.Sdl from Tao.Sdl

class SDLEventLoop (EventLoop):
	override def Run ():
		SDL.Window.ResumeDrawing()
		while true:
			SDL.Window.PauseDrawing()
			
			e as SDL_Event
			// Handle events from SDL
			Handle(e) while SDL_PollEvent(e)
			// Handle other events
			Handle(Queue.Dequeue()) while Queue.Count > 0
			
			SDL.Window.ResumeDrawing()
			System.GC.Collect()
			
			Thread.CurrentThread.Sleep(10)
	
	override def Do (e as object):
		Queue.Enqueue(e)

	override def Handle (ev as object):
		if ev isa SDL_Event:
			e = cast(SDL_Event, ev)
			if e.type == SDL_QUIT:
					Tool.Quit()
				elif e.type == SDL_VIDEORESIZE:
					SDL.Window.Rect = Rect(0,0, e.resize.w, e.resize.h)
				elif e.type == SDL_MOUSEMOTION:
					SDL.Window.MouseMotion(e.motion.x, e.motion.y)
				elif e.type == SDL_APPMOUSEFOCUS:
					if e.active.gain == 1:
						//print "SDL enter"
						SDL.Window.MouseEnter()
					else:
						//print "SDL leave"
						//Gadget.PreviousGadgetUnderMouse = Gadget.GadgetUnderMouse
						//Gadget.GadgetUnderMouse = null
						SDL.Window.MouseLeave()
				elif e.type == SDL_MOUSEBUTTONDOWN:
					b as MouseButton
					b = MouseButton.Left if e.button.button == 1
					b = MouseButton.Right if e.button.button == 3
					SDL.Window.MouseDown(b, e.button.x, e.button.y)
				elif e.type == SDL_MOUSEBUTTONUP:
					//b as MouseButton
					b = MouseButton.Left if e.button.button == 1
					b = MouseButton.Right if e.button.button == 2
					SDL.Window.MouseUp(b, e.button.x, e.button.y)	
				elif e.type == SDL_KEYUP:
					SDL.Window.KeyUp(cast(char,e.key.keysym.unicode), Tool.SDLToKey(e.key.keysym.sym))
				elif e.type == SDL_KEYDOWN:
					SDL.Window.KeyDown(cast(char,e.key.keysym.unicode), Tool.SDLToKey(e.key.keysym.sym))
				elif e.type == SDL_USEREVENT:
					try:
						_C = cast(System.Runtime.InteropServices.GCHandle, e.user.data1)
						_T = cast(System.Runtime.InteropServices.GCHandle, e.user.data2)
						c as callable(UITimer) = _C.Target
						t as UITimer = _T.Target
						c(t)
					except e:
						print "-WARNING- unhandled exception in user event/UI timer:"
						print e
		else:
			super(ev)

class SDL (Frame):
	public Screen as IntPtr
	public RawSurface as IntPtr
	public SdlSurface as IntPtr
	public Canvas as BitmapCanvas
	
	public static Window as SDL = null
	
	public Mouse as Position
	
	public static event_loop as SDLEventLoop
	override EventLoop as EventLoop:
		get:
			return event_loop
	
	Title as string:
		get:
			a as string
			b as string
			SDL_WM_GetCaption(a, b)
			return a
		set:
			SDL_WM_SetCaption(value, null)
	
	override Rect as Rect:
		set:
			Screen = SDL_SetVideoMode(value.Width, value.Height, 32, SDL_RESIZABLE | SDL_SWSURFACE)
			if RawSurface != IntPtr.Zero:
				System.Runtime.InteropServices.Marshal.FreeHGlobal(RawSurface)
			RawSurface = System.Runtime.InteropServices.Marshal.AllocHGlobal(4*value.Width*value.Height)
			SdlSurface = SDL_CreateRGBSurfaceFrom(RawSurface, value.Width, value.Height, 32, value.Width*4, 0xff<<16, 0xff<<8, 0xff, 0xff<<24)
			Canvas = BitmapCanvas(RawSurface, BitmapCanvas.Format.ARGB32, value.Width, value.Height, value.Width*4)
			
			super(value)
	
	def constructor (w as int, h as int):
		if Window != null:
			raise Exception("Only one SDL window can exist at one time!")
		
		Window = self
		super(null)
		DrawFrame = false
		Rect = Vanilla.UI.Rect(0,0,w,h)
		
		PauseDrawing()
	
	public static TotalRedraws = 0
	public static RealRedraws = 0
	
	override def RedrawArea (r as Rect):
		TotalRedraws++
		return if r.Width <= 0 or r.Height <= 0
	
		if DrawingPaused:
			dirty_area += r
			return
		
		//print "REDRAW ${r}"
		
		RealRedraws++
		
		SDL_LockSurface(SdlSurface)
		
		using b = Brush(Canvas):
			b.Draw(Vanilla.UI.Rect(r.X-1, r.Y-1, r.X2+1, r.Y2+1))
			b.Clip()
			b.Colour = Colour.Green
			b.Paint()
			Draw(b)
			/* -- gadget being dragged is now a real child
			unless GadgetBeingDragged is null:
				b.Translate(Mouse.X, Mouse.Y)
				b.Draw(Vanilla.UI.Rect(GadgetBeingDragged.Size))
				b.Clip()
				GadgetBeingDragged.Draw(b)
			*/
		
		
		
		SDL_UnlockSurface(SdlSurface)
		
		try:
			x as int= Math.Max(cast(int,r.X),0)
			y as int = Math.Max(cast(int,r.Y),0)
			x2 as int = Math.Max(cast(int,Math.Min(r.Width+r.X,Rect.Width)), x)
			y2 as int = Math.Max(cast(int,Math.Min(r.Height+r.Y,Rect.Height)), y)
		except e as ArithmeticException:
			return
		
		//print "--> ${x},${y} ${x2}x${y2}"
		
		src = SDL_Rect(x, y, x2-x, y2-y)
		dest = src
		SDL_BlitSurface(SdlSurface, src, Screen, dest)
		SDL_UpdateRect(Screen, x, y, x2-x, y2-y)
	
	override def MouseMotion (x as double, y as double):
		Mouse = Position(x,y)
		unless GadgetBeingDragged is null:
			GadgetBeingDragged.Position = Position(Mouse.X + 1, Mouse.Y + 1)
			//print "GBD.Pos=${GadgetBeingDragged.Position} .Order=${GadgetBeingDragged.Order} .Parent type=${GadgetBeingDragged.Parent}"
		
		super(x,y)
	
	static def constructor ():
		SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER)
		SDL_EnableUNICODE(1)
		event_loop = SDLEventLoop()
		//System.Threading.Thread({event_loop.Run()}).Start()
		event_loop.Do({print "whoop"})

// UI TIMER
/*class UITimer (Vanilla.Timer):
	_C as System.Runtime.InteropServices.GCHandle
	_T as System.Runtime.InteropServices.GCHandle

	def constructor (ticks as int, cb as callable(UITimer), repeat as bool):
		_T = System.Runtime.InteropServices.GCHandle.Alloc(self)
		
		__cb = def (t as UITimer):
			cb(t)
			t.Stop() unless repeat
		
		_C = System.Runtime.InteropServices.GCHandle.Alloc(__cb)
		
		_cb = def (t as Timer):
			e as SDL_Event
			e.type = SDL_USEREVENT
			e.user.data1 = cast(IntPtr, _C)
			e.user.data2 = cast(IntPtr, _T)
			SDL_PushEvent(e)
			Stop() unless repeat
		
		super(ticks,_cb,repeat)
	
	def constructor (ticks as int, cb as callable(UITimer)):
		self(ticks, cb, true)
	
	override def Stop ():
		super()
		_C.Free()
		_T.Free()*/
class UITimer (Vanilla.Timer):
	def constructor (ticks as int, cb as callable(UITimer), repeat as bool):
		super(ticks, repeat, {SDL.Window.event_loop.Do({cb(self)})})
	
	def constructor (ticks as int, cb as callable(UITimer)):
		self(ticks, cb, true)
	

// TOOL
class Tool (Vanilla.Tool):
	public static CurrentDesktop as Desktop

	private static def ContainsAnotherMouseMotion (e as (SDL_Event)):
		pass

	static def SDLToKey (s as int):
		if s == SDLK_SPACE:
			return Key.Space
		elif s == SDLK_RETURN:
			return Key.Enter

	static def Run ():
		SDL.Window.event_loop.Run()
		
		#SDL.Window.ResumeDrawing()
		#
		#while true:
		#	e as SDL_Event
		#	SDL_WaitEvent(e)
		#	events as (SDL_Event) = (e,)
		#	
		#	while SDL_PollEvent(e):
		#		events += (e,)
		#	
		#	SDL.Window.PauseDrawing()
		#		
		#	for e in events:
		#		SDL.Window.event_loop.Do(e)
		#	
		#	SDL.Window.event_loop.WaitUntilPendingEventsAreHandled()
		#	
		#	SDL.Window.ResumeDrawing()
		#	System.GC.Collect()
		#	
		#	//if Gadget.GadgetWithMouseGrabbed != null:
		#	//	SDL_WM_GrabInput(SDL_GRAB_ON)
		#	//else:
		#	//	SDL_WM_GrabInput(SDL_GRAB_OFF)
			
	static def Quit ():
		SDL.Window.event_loop.Thread.Abort()
		SDL_Quit()
		print "redraws - real/total: ${SDL.RealRedraws}/${SDL.TotalRedraws}"
		print "total packs - ${Gadget.packing_count}"
		System.Environment.Exit(0)

